import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import WipOrderReport from '@main/entities/service/admin/wip/wip-order-report.entity';
import ProductionOrder from '@main/entities/service/admin/production/production-order.entity';
// import { BaseMachineService } from './../../../admin/base/machine/machine.service';
import { Repository } from 'typeorm';
import { format } from 'date-fns';
import BaseMachine from '@main/entities/service/admin/base/base-machine.entity';
import BaseShift from '@main/entities/service/admin/base/base-shift.entity';
import WipShutdownList from '@main/entities/service/admin/wip/wip-shutdown-list.entity';
import { SysParamConfigService } from '../../system/paramConfig/paramConfig.service';
import WipBadRegistration from '@main/entities/service/admin/wip/wip-bad-registration.entity';
import WipBadRegistrationList from '@main/entities/service/admin/wip/wip-bad-registration-list.entity';

@Injectable()
export class ReportFormMonthlySummaryService {
  constructor(
    private paramConfig: SysParamConfigService,
    @InjectRepository(WipOrderReport)
    private orderReportRepository: Repository<WipOrderReport>,
    @InjectRepository(BaseMachine)
    private machineRepository: Repository<BaseMachine>,
    @InjectRepository(BaseShift) private shiftRepository: Repository<BaseShift>,
    @InjectRepository(ProductionOrder)
    private orderRepository: Repository<ProductionOrder>,
    @InjectRepository(WipShutdownList)
    private shutdownListRepository,
    @InjectRepository(WipBadRegistration)
    private badRegistrationRepository: Repository<WipBadRegistration>,
    @InjectRepository(WipBadRegistrationList)
    private badRegistrationListRepository: Repository<WipBadRegistrationList>
  ) {}

  /**
   * 罗列所有配置
   */
  async list(data) {
    const { entity = {} } = data;

    const { machineCode, month, shiftCode } = entity;

    const monthDate = new Date(month); // e.g., 2025-01
    const year = monthDate.getFullYear();
    const month1 = monthDate.getMonth(); // getMonth() 返回 0 为1月，11 为12月

    // 获取当月的第一天
    const startOfMonth = new Date(year, month1, 1); // 设定为当月的第一天
    startOfMonth.setHours(0, 0, 0, 0); // 确保时间是 00:00:00

    // 获取下个月的第一天
    const nextMonth = new Date(year, month1 + 1, 1); // 设定为下个月的第一天

    // 获取当月最后一天的 23:59:59
    const endOfMonth = new Date(nextMonth); // 以下个月的第一天为基础
    endOfMonth.setMilliseconds(endOfMonth.getMilliseconds() - 1); // 将时间调整为当月最后一刻

    const sql = `
      SELECT *
        FROM wip_order_report AS report
        WHERE report.machine_code = '${machineCode}'
          AND report.report_finish_status = 1
          AND report.shift_code = '${shiftCode}'
          AND report.report_time BETWEEN strftime('%s', '${format(
            new Date(startOfMonth),
            'yyyy-MM-dd HH:mm:ss'
          )}') * 1000 AND strftime('%s', '${format(
      new Date(endOfMonth),
      'yyyy-MM-dd HH:mm:ss'
    )}') * 1000
      `;

    const list = await this.orderReportRepository.query(sql);

    if (!list.length) {
      return null;
    }

    const reportDateList = [];

    const orderList = [];

    //   1）开始日期：选择月份的第一天；

    // 2）结束日期：选择月份的最后一天

    // 3）累计工作天数：当前设备当前班组当月有报工记录的天数

    // 4）累计工作时间(h)：工作天数*出勤时数，出勤时数在参数管理中配置，保留两位小数；

    // 5)  累计生产用时(h)：当前机台当前班组当月所有报工的生产用时之和，保留两位小数；

    // 6)  累计调机用时(h)：当前机台当前班组当月所有报工的调机用时之和，保留两位小数；

    // 7)  累计停机时长(h)：当前机台当前班组当月所有报工的停机时长之和，保留两位小数；

    // 8) 有效生产用时(h)：累计生产用时(h)-累计停机时长(h)，保留两位小数；

    // 9) 平均调机用时(min)：累计调机用时(h)/累计完工工单数，保留两位小数；

    // 10)平均速度(pcs/min)：累计投入数/累计生产用时，保留0位小数，注意这里的累计生产用时单位是min；

    // 11）累计完工工单数：当前班组当月在当前机台所有完工工单数；

    // 11) 累计完工数量：当前机台当前班组当月所有报工的当班完工数量之和；

    // 12) 累计良品数：当前机台当前班组当月所有报工的报工数量之和；

    // 13) 累计良品率=累计良品数/累计完工数量*100%，百分数保留2位小数；

    // 14) 累计良品面积(㎡)：当前机台当前班组当月所有报工单的（良品数量/模数*单张纸板面积）之和，保留两位小数；如果纸板规格单位为inch，需转换为㎡-2022-02-18

    // 15)累计良品产值：当前机台当前班组当月所有报工单的（良品数量*产品单价）之和，保留两位小数；

    // 16) 累计用电量(kW.h)：当前机台当前班组当月所有报工单的用电量之和，保留两位小数；

    // 17) 累计电费=累计用电量*电价 （电价在参数管理中配置），保留两位小数；

    // 18) 累计用水量(t)：当前机台当前班组当月所有报工单的用水量之和，保留两位小数；

    // 19) 累计水费=累计用水量*水价   （水价在参数管理中配置），保留两位小数；

    // 20) 累计水墨总用量：当前机台当前班组当月所有报工单的各水墨用量之和，保留两位小数；

    // 21) 累计水墨费用：当前机台当前班组当月所有报工单的各水墨成本（水墨用量1*水墨单价1+水墨用量2*水墨单价2+...）之和，保留两位小数；

    // 22) 累计人工成本：当前机台当前班组当前所有报工单的人工成本之和，人工成本=（工单生产时间/60*各岗位小时人工成本之和），保留两位小数；

    // 23) 累计加工成本=累计电费+累计水费+累计水墨费用+累计人工成本，保留两位小数；

    let totalPowerConsumption = 0; // 累计用电量(kW.h)

    let totalElectricityCost = 0; // 累计电费

    let totalWaterConsumption = 0; // 累计用水量(t)

    let totalWaterCost = 0; // 累计水费

    let totalCompletedQTY = 0; // 累计完工数量

    let totalProductionTime = 0; // 累计生产用时(h)

    let totalYieldQTY = 0; // 累计良品数

    let totalInkConsumption = 0; // 累计水墨总用量

    let totalTestingTime = 0; // 总调机用时(min)

    const totalInkCost = 0; // 累计水墨费用 todo

    let totalDowntimeDurationH = 0; // 累计停机时长(h)

    let totalYieldArea = 0; // 累计良品面积(㎡)

    let totalLaborCosts = 0; // 累计人工成本

    let totalEffectiveProductionTime = 0; // 累计有效生产用时(h)

    let totalYieldValue = 0; // 累计良品产值

    const reportMonthComprehensiveBadList = []; // 不良现象分析

    const reportMonthComprehensiveDownList = []; // 停机原因分析

    const reportMonthComprehensiveCorrugatedList = []; // 瓦楞类型分析

    let allShutdownDuration = 0; // 累计停机时长(min)

    await Promise.all(
      list.map(async (item) => {
        const {
          report_code: reportCode,
          report_time: reportTime,
          order_code: orderCode,
          report_num: reportNum,
          report_status: reportStatus,
          report_confirm_num: reportConfirmNum,
          good_num: goodNum,
          electricity_consumption: electricityConsumption,
          water_consumption: waterConsumption,
          electricity_bill: electricityBill,
          water_bill: waterBill,
          ink_usage: inkUsage,
          labor_cost: laborCost,
          adjuest_duration: adjuestDuration,
          create_time: createTime,
        } = item;

        let shutdownTime = 0;

        const shutdownList = await this.shutdownListRepository.find({ where: { reportCode } });

        for (let k = 0; k < shutdownList.length; k++) {
          const { shutdownDuration, shutdownReasonCode, shutdownReasonName } = shutdownList[k];

          shutdownTime += shutdownDuration || 0;

          const obj = reportMonthComprehensiveDownList.find(
            (item) => item.shutdownReasonCode === shutdownReasonCode
          );

          if (obj) {
            obj.shutdownDuration += shutdownDuration || 0;
          } else {
            reportMonthComprehensiveDownList.push({
              shutdownReasonCode,
              shutdownDuration: shutdownDuration || 0,
              shutdownReasonName,
            });
          }
        }

        allShutdownDuration += shutdownTime;

        totalDowntimeDurationH += shutdownTime / 60;

        const date = format(new Date(reportTime), 'yyyy-MM-dd');

        if (!reportDateList.includes(date)) {
          reportDateList.push(date);
        }

        if (!orderList.includes(orderCode)) {
          orderList.push(orderCode);
        }

        if (adjuestDuration) {
          totalTestingTime += adjuestDuration;
        }

        if (electricityConsumption) {
          totalPowerConsumption += electricityConsumption;
        }

        if (electricityBill) {
          totalElectricityCost += electricityBill;
        }

        if (waterConsumption) {
          totalWaterConsumption += waterConsumption;
        }

        if (waterBill) {
          totalWaterCost += waterBill;
        }

        // console.log(totalProductionTime);

        totalProductionTime +=
          (new Date(reportTime).getTime() - new Date(createTime).getTime()) / 1000 / 60 / 60;

        totalEffectiveProductionTime += totalProductionTime - totalDowntimeDurationH;

        if (reportStatus === 1) {
          totalCompletedQTY += reportConfirmNum;
        } else {
          totalCompletedQTY += reportNum;
        }

        if (goodNum) {
          totalYieldQTY += goodNum;
        }

        if (inkUsage) {
          totalInkConsumption += inkUsage;
        }

        if (laborCost) {
          totalLaborCosts += laborCost;
        }

        const obj = await this.orderRepository.findOne({
          where: { orderCode },
        });

        if (obj) {
          const { paperLength, paperWidth, templateNum = 1, materialPrice = 0 } = obj;

          totalYieldArea +=
            (goodNum / (templateNum ? templateNum : 1)) * (paperLength * paperWidth);

          if (materialPrice) {
            totalYieldValue += goodNum * materialPrice;
          }
        }
      })
    );

    if (orderList.length) {
      let allBadNum = 0;

      let allCardBoardArea = 0;

      let allCardboardQTY = 0;

      await Promise.all(
        orderList.map(async (orderCode) => {
          const badList = await this.badRegistrationRepository.find({
            where: { orderCode },
          });

          if (badList && badList.length) {
            for (const item of badList) {
              const { badRegistrationCode } = item;

              const badRegistrationList = await this.badRegistrationListRepository.find({
                where: {
                  badRegistrationCode,
                },
              });

              if (badRegistrationList && badRegistrationList.length) {
                for (const bItem of badRegistrationList) {
                  const { badCode, badNum } = bItem;

                  const obj = reportMonthComprehensiveBadList.find(
                    (item) => item.badCode === badCode
                  );

                  allBadNum += badNum;

                  if (obj) {
                    obj.badNum += badNum;
                  } else {
                    reportMonthComprehensiveBadList.push(bItem);
                  }
                }
              }
            }
          }

          const obj = await this.orderRepository.findOne({
            where: {
              orderCode,
            },
          });

          if (obj) {
            const {
              corrugatedTypeName,
              corrugatedTypeCode,
              paperLength,
              paperWidth,
              paperboardNum,
            } = obj;

            const obj1 = reportMonthComprehensiveCorrugatedList.find(
              (item) => item.corrugatedTypeCode === corrugatedTypeCode
            );

            const totalCardBoardArea = paperLength * paperWidth * paperboardNum;

            // const totalDowntimeDuration = paperboardNum;

            allCardboardQTY += paperboardNum;

            allCardBoardArea += totalCardBoardArea;

            if (obj1) {
              obj1.paperboardNum += paperboardNum;

              obj1.totalCardBoardArea += totalCardBoardArea;
            } else {
              reportMonthComprehensiveCorrugatedList.push({
                corrugatedTypeName,
                corrugatedTypeCode,
                paperboardNum,
                totalCardBoardArea,
              });
            }
          }
        })
      );

      reportMonthComprehensiveBadList.forEach((item, key) => {
        const { badNum } = item;

        item.badRate = ((badNum / allBadNum) * 100).toFixed(2) + '%';

        item.index = key + 1;
      });

      reportMonthComprehensiveCorrugatedList.forEach((item, key) => {
        const { paperboardNum, totalCardBoardArea } = item;

        item.paperboardRate = ((paperboardNum / allCardboardQTY) * 100).toFixed(2) + '%';

        item.totalCardBoardAreaRate =
          ((totalCardBoardArea / allCardBoardArea) * 100).toFixed(2) + '%';

        item.index = key + 1;
      });
    }

    reportMonthComprehensiveDownList.forEach((item, key) => {
      const { shutdownDuration } = item;

      item.shutdownRate = (allShutdownDuration  === 0 ? 0 : ((shutdownDuration / allShutdownDuration) * 100)).toFixed(2) + '%';

      item.index = key + 1;
    });

    const totalWorkingDays = reportDateList.length; // 累计工作天数

    const totalCompletedWO = orderList.length; // 累计完工工单数

    const totalProductionCost =
      totalElectricityCost + totalWaterCost + totalInkCost + totalLaborCosts; // 累计加工成本

    const totalYieldRate = ((totalYieldQTY / totalCompletedQTY) * 100).toFixed(2) + '%'; // 累计良品率

    const attendanceHours: any = (await this.paramConfig.findValueByCode('attendanceHours')) || 8;

    const totalWorkingTime = totalWorkingDays * attendanceHours; // 累计工作时间(h)

    const avgTestingTime = totalTestingTime / totalCompletedWO; // 平均调机用时(min)

    const avgSpeed = totalCompletedQTY / (totalProductionTime * 60); // 平均速度(pcs/min)

    const shiftName =
      (await this.shiftRepository.findOne({ where: { shiftCode } }))?.shiftName || '';

    const machineName =
      (await this.machineRepository.findOne({ where: { machineCode } }))?.machineName || '';

    const comprehenPerformance = {
      totalPowerConsumption: totalPowerConsumption.toFixed(2),
      totalElectricityCost: totalElectricityCost.toFixed(2),
      totalWaterConsumption: totalWaterConsumption.toFixed(2),
      totalWaterCost: totalWaterCost.toFixed(2),
      totalCompletedQTY,
      totalProductionTime: totalProductionTime.toFixed(2),
      totalYieldQTY,
      totalInkConsumption: totalInkConsumption.toFixed(2),
      totalTestingTime: totalTestingTime.toFixed(2),
      totalInkCost: totalInkCost.toFixed(2),
      totalDowntimeDurationH: totalDowntimeDurationH.toFixed(2),
      totalYieldArea: totalYieldArea.toFixed(2),
      totalLaborCosts: totalLaborCosts.toFixed(2),
      totalEffectiveProductionTime: totalEffectiveProductionTime.toFixed(2),
      totalYieldValue: totalYieldValue.toFixed(2),
      totalWorkingDays,
      totalCompletedWO,
      totalProductionCost: totalProductionCost.toFixed(2),
      totalYieldRate,
      totalWorkingTime: totalWorkingTime.toFixed(2),
      avgTestingTime: avgTestingTime.toFixed(2),
      avgSpeed: avgSpeed.toFixed(2),
      shiftName,
      machineName,
    };

    return {
      comprehenPerformance,
      reportMonthComprehensiveBadList,
      reportMonthComprehensiveDownList,
      reportMonthComprehensiveCorrugatedList,
    };
  }
}
